package com.zqh.template.maker;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.zqh.meta.Meta;
import com.zqh.meta.enums.FileTypeEnum;
import com.zqh.template.enums.FileFilterRangeEnum;
import com.zqh.template.enums.FileFilterRuleEnum;
import com.zqh.template.filter.Distinct;
import com.zqh.template.filter.FileFilter;

import com.zqh.template.model.*;
import com.zqh.template.utils.TemplateMakerUtils;
import lombok.var;

import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


import static com.zqh.template.maker.FileMaker.makeFileTemplate;


public class TemplateMaker {

    /**
     * 制作模板（方法重载）
     *
     * @param templateMakerConfig
     * @return
     */
    public static long makeTemplate(TemplateMakerConfig templateMakerConfig) {
        Meta meta = templateMakerConfig.getMeta();
        String originProjectPath = templateMakerConfig.getOriginProjectPath();
        TemplateMakerFileConfig templateMakerFileConfig = templateMakerConfig.getFileConfig();
        TemplateMakerModelConfig templateMakerModelConfig = templateMakerConfig.getModelConfig();
        TemplateMakerOutputConfig templateMakerOutputConfig = templateMakerConfig.getOutputConfig();
        Long id = templateMakerConfig.getId();

        return makeTemplate(meta, originProjectPath, templateMakerFileConfig, templateMakerModelConfig, templateMakerOutputConfig, id);
    }


    /**
     * @description: 模板制作
     * @params: [newMeta,
     * projectPath,
     * originSourceRootPath,
     * templateMakerFileConfig,
     * templateMakerModelConfig,
     * id]
     * @return: long
     * @author: zqh
     * @dateTime: 2025/2/25 15:02
     */
    public static long makeTemplate(Meta newMeta,
                                    String originSourceRootPath,
                                    TemplateMakerFileConfig templateMakerFileConfig,
                                    TemplateMakerModelConfig templateMakerModelConfig,
                                    TemplateMakerOutputConfig templateMakerOutputConfig,
                                    Long id) {


        // 没有ID则生成
        if (id == null || id == 0) {
            id = IdUtil.getSnowflakeNextId();
//            System.out.println(id);
        }

        // 复制目录
        var projectPath = System.getProperty("user.dir");
        var tempDirPath = projectPath + "/" + ".temp";
        var templatePath = tempDirPath + "/" + id;

        // 是否首次制作模板
        // 目录不存在，则是首次制作
        if (!FileUtil.exist(templatePath)) {
            FileUtil.mkdir(tempDirPath);
            // 复制目录过来
            FileUtil.copy(originSourceRootPath, templatePath, true);

        }

        // 一、输入信息
        // 输入文件信息
//        FileUtil.getLastPathEle最后一个子路径部分
//        String sourceRootPath = templatePath + "/" +
//                FileUtil.getLastPathEle(Paths.get(originSourceRootPath)).toString();

        // 获取目录的第一个路径
        String sourceRootPath = FileUtil.loopFiles(new File(templatePath),1,null)
                .stream()
                .filter(file -> file.isDirectory())
                .findFirst()
                .orElseThrow(RuntimeException::new)
                .getAbsolutePath();


        // 制作文件你模板
        List<Meta.FileConfig.FilesInfo> newfilesInfoList =
                makeFileTemplates(templateMakerFileConfig, templateMakerModelConfig, sourceRootPath);

        // 处理模型信息
        var newModelInfoList = getModelsInfoList(templateMakerModelConfig);


        String metaOutputPath = templatePath + "/" + "meta.json";

        // 1、构造配置参数
        // 总体配置
        if (FileUtil.exist(metaOutputPath)) {

            // 追加配置参数
            Meta oldMeta = JSONUtil.toBean(FileUtil.readUtf8String(metaOutputPath), Meta.class);

            // 新老对象合并
            BeanUtil.copyProperties(newMeta, oldMeta, CopyOptions.create().ignoreNullValue());
            newMeta = oldMeta;

            List<Meta.FileConfig.FilesInfo> filesInfoList = newMeta.getFileConfig().getFiles();
            filesInfoList.addAll(newfilesInfoList);
            List<Meta.ModelConfig.ModelsInfo> modelsInfoList = newMeta.getModelConfig().getModels();
            modelsInfoList.addAll(newModelInfoList);

            // 配置去重
            newMeta.getFileConfig().setFiles(Distinct.distinctFiles(filesInfoList)); // 文件去重
            newMeta.getModelConfig().setModels(Distinct.distinctModels(modelsInfoList)); // 模型去重


        } else {

            // 文件配置
            Meta.FileConfig fileConfig = new Meta.FileConfig();
            newMeta.setFileConfig(fileConfig);
            fileConfig.setSourceRootPath(sourceRootPath);
            List<Meta.FileConfig.FilesInfo> filesInfoList = new ArrayList<>();

            fileConfig.setFiles(filesInfoList);

            filesInfoList.addAll(newfilesInfoList); // 添加filesInfoList列表

            // 模型配置
            var modelConfig = new Meta.ModelConfig();
            newMeta.setModelConfig(modelConfig);
            List<Meta.ModelConfig.ModelsInfo> modelsInfoList = new ArrayList<>();
            modelConfig.setModels(modelsInfoList);
            modelsInfoList.addAll(newModelInfoList);

        }

        // 2、额外的输出配置
        if(templateMakerOutputConfig != null){
            // 文件外层和分组去重
            if(templateMakerOutputConfig.isRemoveGroupFilesFromRoot()){
                var filesInfoList = newMeta.getFileConfig().getFiles();
                newMeta.getFileConfig().setFiles(TemplateMakerUtils.removeGroupFilesFromRoot(filesInfoList));
            }
        }

        // 更新元信息  通过mete类，生成Meta信息的json文件
        FileUtil.writeUtf8String(JSONUtil.toJsonPrettyStr(newMeta), metaOutputPath);


        return id;
    }


    /**
     * @description: 处理模型信息
     * @params: [templateMakerModelConfig]
     * @return: java.util.ArrayList<com.zqh.meta.Meta.ModelConfig.ModelsInfo>
     * @author: zqh
     * @dateTime: 2025/4/29 15:34
     */
    private static ArrayList<Meta.ModelConfig.ModelsInfo> getModelsInfoList(TemplateMakerModelConfig templateMakerModelConfig) {


        // 本次新增的模型配置列表
        var newModelInfoList = new ArrayList<Meta.ModelConfig.ModelsInfo>();
        if (templateMakerModelConfig == null) return newModelInfoList;

        // 处理模型信息 List<ModelInfoConfig> models;
        var models = templateMakerModelConfig.getModels();
        if(CollUtil.isEmpty(models)) return newModelInfoList;

        // 转化配置接受的ModelInfo 对象
        var inputModelsInfoList = models
                .stream()
                .map(
                        modelInfoConfig -> {
                            var modelInfo = new Meta.ModelConfig.ModelsInfo();
                            BeanUtil.copyProperties(modelInfoConfig, modelInfo);
                            return modelInfo;
                        }
                ).collect(Collectors.toList());


        // 如果是模型组
        var modelGroupConfig = templateMakerModelConfig.getModelGroupConfig();
        if (modelGroupConfig != null) {


            // 复制变量
            var groupModelInfo = new Meta.ModelConfig.ModelsInfo();
            BeanUtil.copyProperties(modelGroupConfig, groupModelInfo);

            // 模型放到一个分组内
            groupModelInfo.setModels(inputModelsInfoList);
            newModelInfoList.add(groupModelInfo);

        } else {
            // 不分组，添加所有模型到列表
            newModelInfoList.addAll(inputModelsInfoList);
        }
        return newModelInfoList;
    }

    /**
     * @description: 生成多个文件
     * @author: zqh
     * @dateTime: 2025/4/29 15:21
     */
    private static List<Meta.FileConfig.FilesInfo> makeFileTemplates(TemplateMakerFileConfig templateMakerFileConfig, TemplateMakerModelConfig templateMakerModelConfig,
                                                                     String sourceRootPath) {


        // 输入文件目录
        List<Meta.FileConfig.FilesInfo> newfilesInfoList = new ArrayList<>();

        // 非空校验
//        if (templateMakerFileConfig == null) return newfilesInfoList;
        var fileInfoConfigList = templateMakerFileConfig.getFiles();
        if (CollUtil.isEmpty(fileInfoConfigList)) return newfilesInfoList;

        for (var fileInfoConfig : fileInfoConfigList) {
            String fileInputPath = fileInfoConfig.getPath();
            // 如果填的是相对路径，要改为绝对路径
            if (!fileInputPath.startsWith(sourceRootPath)) {
                fileInputPath = sourceRootPath + '/' + fileInputPath;
            }
            // 过滤后的文件列表，不会存在目录（不处理已经生成的ftl文件）
            List<File> fileList = FileFilter.doFilter(fileInputPath, fileInfoConfig.getFilterConfigList())
                    .stream()
                    .filter(file -> !file.getAbsolutePath().endsWith(".ftl"))
                    .collect(Collectors.toList());

            for (File file : fileList) {
                Meta.FileConfig.FilesInfo filesInfo = makeFileTemplate(templateMakerModelConfig, sourceRootPath, file,fileInfoConfig);
                newfilesInfoList.add(filesInfo);
            }

        }

        // 如果是文件组
        // 获取模板制作文件配置中的文件组配置
        TemplateMakerFileConfig.FileGroupConfig fileGroupConfig = templateMakerFileConfig.getFileGroupConfig();
        // 检查文件组配置是否存在
        if (fileGroupConfig != null) {
            // 获取文件组配置的条件、组键和组名
            String condition = fileGroupConfig.getCondition();
            String groupKey = fileGroupConfig.getGroupKey();
            String groupName = fileGroupConfig.getGroupName();

            // 新增分组配置
            var groupFileInfo = Meta.FileConfig.FilesInfo
                    .builder()
                    .groupKey(groupKey).groupName(groupName).condition(condition)
                    .type(FileTypeEnum.GROUP.getValue())
                    .build();

            // 文件全部放在一个分组中
            groupFileInfo.setFiles(newfilesInfoList);
            // 重置文件信息列表，以便后续使用
            newfilesInfoList = new ArrayList<>();
            // 将新建的分组信息添加到文件信息列表中
            newfilesInfoList.add(groupFileInfo);

        }
        return newfilesInfoList;
    }


}
